04服务端Socket的`bind()`、`listen()`、`accept()`方法分别有什么作用?
文章目录
问题: Socket的bind()、listen()、accept()方法分别有什么作用?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
调用顺序与底层状态转换
- **bind()**:在调用
socket()创建套接字后,该套接字处于未命名状态(无 IP 和端口)。bind()为其分配本地地址,使内核能够将接收到的网络包(目标端口匹配)递交给该套接字。 - **listen()**:将套接字从主动连接(可发起
connect)切换为被动连接(可接收connect),内核为该套接字维护两个队列:未完成队列(SYN_RCVD 半连接)和已完成队列(ESTABLISHED 全连接)。 - **accept()**:默认阻塞当前线程,从已完成队列中取出队首连接并返回。若队列为空,进程进入睡眠状态,直到有新连接到达。
代码流程与参数说明
1 | import socket |
三个方法的职责与约束速览
| 方法 | 前置条件 | 核心职责 | 后续操作 |
|---|---|---|---|
bind() |
套接字未绑定 | 注册本地地址和端口,供客户端寻址 | 必须调用 listen() |
listen() |
已 bind() |
激活被动模式,初始化连接队列 | 必须调用 accept() |
accept() |
已 listen() |
阻塞获取客户端新连接,分配新套接字 | 使用新套接字收发数据 |
高频追问:accept() 返回的套接字和原套接字有何区别?
- 原监听套接字(Server Socket)职责单一,仅负责监听和接收新连接,始终保持
listen状态,不应使用它收发数据。 - 返回的新套接字(Client Socket)专门服务于该客户端,负责该连接的
send()和recv()操作,关闭后不影响监听套接字,服务端仍可继续accept()接收其他客户端。
常见异常场景
- 端口占用(Address already in use):
bind()指定端口已被其他进程占用,可通过SO_REUSEADDR选项重用。 - Backlog 溢出:
listen(backlog)过小,在高并发下已完成队列满,新连接可能被拒绝,需根据业务调整。 - 阻塞挂起:
accept()默认阻塞,服务端无法执行其他任务,如需超时控制,可设置settimeout()或使用非阻塞模式配合select/epoll。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 LGQ的博客!